package com.tuyrt.firstcode.kotlin.functions

/**
 * Created by tuyrt7 on 2021/4/6.
 * 标准函数 let、with、run、apply、also
 */

/** 使用
let     : inline fun <T, R> T.let(block: (T) -> R): R  ，返回值是block表达式的返回值，
适用：1、配合 ?. 辅助判空操作 2、明确变量所处特定的作用域范围
let -->
mVideoPlayer?.let {
    it.setVideoView(activity.course_video_view)
    it.setControllerView(activity.course_video_controller_view)
    it.setCurtainView(activity.course_video_curtain_view)
}


with    : inline fun <T, R> with(receiver: T, block: T.() -> R): R ，返回值是block表达式的返回值，
适用：调用同一个类的多个方法时，可以省去类名重复，直接调用类的方法即可，经常用于Android中RecyclerView中onBinderViewHolder中，数据model的属性映射到UI上
with -->
override fun onBindViewHolder(holder: ViewHolder, position: Int){
    val item = getItem(position)?: return
    with(item){
        holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
        holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
        holder.tvExtraInf.text = "难度：$gradeInfo | 单词数：$length | 读后感: $numReviews"
        ...
    }
}


run     : inline fun <T, R> T.run(block: T.() -> R): R ，返回值是block表达式的返回值
适用：let,with函数任何场景
run -->
override fun onBindViewHolder(holder: ViewHolder, position: Int){
    getItem(position)?.run{
        holder.tvNewsTitle.text = StringUtils.trimToEmpty(titleEn)
        holder.tvNewsSummary.text = StringUtils.trimToEmpty(summary)
        holder.tvExtraInf = "难度：$gradeInfo | 单词数：$length | 读后感: $numReviews"
        ...
    }
}


apply   : inline fun <T> T.apply(block: T.() -> Unit): T ，返回值是调用的对象，可配合 Intent 传递参数
适用：1、对象实例初始化时候，对对象中的属性进行赋值 2、动态inflate出一个XML的View的时候需要给View绑定数据也会用到，这种情景非常常见。特别是在我们开发中会有一些数据model向View model转化实例化的过程中需要用到。
apply -->
Intent().apply {
    putExtra("key","xxx")
    putExtra("key2","xxx")
}

also    : inline fun <T> T.also(block: (T) -> Unit): T ，返回值是调用的对象
适用：适用于let函数的任何场景，一般可用于多个扩展函数链式调用
also -->

总结：
返回值类型不同 ：
1、返回 Lambda 的返回值: let、with、run
2、返回调用者本身： apply、also

Lambda的作用域中的上下文不同：
 1. it（调用者作为参数传入Lambda 函数）: let、also
 2. this（Lambda 表达式是调用者的扩展方法）:  with、run、apply
 */



fun main() {
    var str: String? = null
    str = "let"
    str?.let {
        println(it)
    }

    //with
    val fruits = listOf("Apple", "Orange")
    val withResult:String = with(StringBuilder()) {
        //StringBuilder 上下文
        append("with has fruit: ")
        fruits.forEach {
            append(it).append(" ")
        }
        toString() //返回值
    }
    println("main with: $withResult")

    val runResult = StringBuilder().run {
        //StringBuilder 上下文
        append("run has fruit: ")
        fruits.forEach {
            append(it).append(" ")
        }
        toString() //返回值
    }
    println("main run: $withResult")

    val applyResult:StringBuilder = StringBuilder().apply {
        //StringBuilder 上下文
        append("apply has fruit: ")
        fruits.forEach {
            append(it).append(" ")
        }
    }
    println("main apply: ${applyResult.toString()}")


    val alsoResult = StringBuilder().also {

    }
}